import {
  h,
  defineComponent,
  reactive,
  onMounted,
  onUnmounted,
} from "@vue/runtime-core";
import TWEEN from "@tweenjs/tween.js";
import Map from "../component/Map";
import Plane, { PlaneInfo } from "../component/Plane";
import EnemyPalne, { enemyPlaneInfo } from "../component/EnemyPalne";
import Bullet, { SelfBulletInfo, EnemyBulltInfo } from "../component/Bullet";
import { game } from "../Game";
import { hitTestObject } from "../utils/index";
import { useKeyboardMove } from "../use/index";
import { stage } from "../config/index";
import { moveBullets } from "../use/moveBullets";
import { moveEnemyPlane } from "../use/moveEnemyPlane";
import { PAGE } from "./index";

let hashCode = 0;
const createHashCode = () => {
  return hashCode++
}

// 只展示 map
export default defineComponent({
  props: ['onChangePage'],
  setup(props, { emit }) {
    // 响应式对象
    // 引用类型——reactive
    // 基本类型——ref
    // 我方飞机
    const planeInfo = usePlaneInfo({
      x: stage.width / 2 - 60,
      y: stage.height,
      speed: 7
    });

    // 敌方飞机
    const enemyPlanes = useCreateEnemyPlanes();

    // 我方子弹
    const { bullets, addBullet, destorySelfBullet } = useCreateBulltes();
    const { enemyBullets, addEnemyBullet } = useCreateEnemyBulltes();

    const gameOverCallBack = () => {
      props.onChangePage(PAGE.end)
    }

    // 战斗逻辑
    useFighting(
      enemyPlanes, 
      bullets, 
      enemyBullets, 
      planeInfo, 
      emit, 
      gameOverCallBack
    );

    // 发射子弹函数
    const onAttack = (bulletInfo) => {
      addBullet(bulletInfo.x, bulletInfo.y);
    };

    return {
      bullets,
      planeInfo,
      enemyPlanes,
      onAttack,
      enemyBullets,
      addEnemyBullet
    };
  },
  render(ctx) {
    // 创建敌方
    const createEnemyPlanes = (info, index) => {
      return h(EnemyPalne, {
        key: 'EnemyPlane' + index,
        x: info.x,
        y: info.y,
        width: info.width,
        height: info.height,
        onAttack({ x, y }) {
          ctx.addEnemyBullet(x, y)
        }
      });
    };

    // 创建我方子弹及敌方子弹
    const createSelfBullets = (info) => {
      return h(Bullet, {
        key: 'Bullet' + info.id,
        x: info.x,
        y: info.y,
        id: info.id,
        width: info.width,
        height: info.height,
        rotation: info.rotation,
        dir: info.dir,
        onDestory({id}) {
          ctx.destorySelfBullet(id)
        }
      });
    };

    return h("Container", [
      h(Map),
      h(Plane, {
        x: ctx.planeInfo.x,
        y: ctx.planeInfo.y,
        speed: ctx.planeInfo.speed,
        onAttack: ctx.onAttack,
      }),
      ...ctx.enemyPlanes.map(createEnemyPlanes),
      ...ctx.enemyBullets.map(createSelfBullets),
      ...ctx.bullets.map(createSelfBullets),
    ]);
  },
});

const usePlaneInfo = ({ x, y, speed }) => {
  const planeInfo = reactive({
    x, 
    y,
    speed, 
    width: PlaneInfo.width, 
    height: PlaneInfo.height 
  });

  // 绑定好要监听的事件及优化移动过程中的卡顿
  const { x: selfPlaneX, y: selfPlaneY } = useKeyboardMove({
    x: planeInfo.x,
    y: planeInfo.y,
    speed: planeInfo.speed
  })

  // 缓慢出场 
  const tween = new TWEEN.Tween({
    x,
    y
  })
    .to({ y: y - 250 }, 500)
    .start()
  tween.onUpdate((obj) => {
    planeInfo.x = obj.x
    planeInfo.y = obj.y
  })

  const handlerTicker = () => {
    TWEEN.update()
  }

  onMounted(() => {
    game.ticker.add(handlerTicker)
  })

  onUnmounted(() => {
    game.ticker.remove(handlerTicker)
  })

  planeInfo.x = selfPlaneX;
  planeInfo.y = selfPlaneY
  
  return planeInfo;
};

// 创建敌机
function useCreateEnemyPlanes() {
  const createEnemyPlaneData = (x) => {
    return {
      x,
      y: -200,
      width: enemyPlaneInfo.width,
      height: enemyPlaneInfo.height,
      life: enemyPlaneInfo.life
    }
  }
  const enemyPlanes = reactive([]);

  setInterval(() => {
    const x = Math.floor((1 + stage.width) * Math.random())
    enemyPlanes.push(createEnemyPlaneData(x))
  }, 600)

  return enemyPlanes;
}

// 创建我方子弹
function useCreateBulltes() {
  const bullets = reactive([]);

  const addBullet = (x, y) => {
    const id = createHashCode();
    const width = SelfBulletInfo.width;
    const height = SelfBulletInfo.height;
    const rotation = SelfBulletInfo.rotation;
    const dir = SelfBulletInfo.dir;
    bullets.push({ x, y, width, height, rotation, dir, id });
  };

  // 销毁子弹
  const destorySelfBullet = (id) => {
    const index = bullets.findIndex(info => info.id == id)
    if (index !== -1) {
      bullets.splice(index, 1)
    }
  }

  return { bullets, addBullet, destorySelfBullet };
}

// 创建敌方子弹
function useCreateEnemyBulltes() {
  const enemyBullets = reactive([]);

  const addEnemyBullet = (x, y) => {
    const id = createHashCode();
    const width = EnemyBulltInfo.width;
    const height = EnemyBulltInfo.height;
    const rotation = EnemyBulltInfo.rotation;
    const dir = EnemyBulltInfo.dir;
    enemyBullets.push({ x, y, width, height, rotation, dir, id });
  };

  return { enemyBullets, addEnemyBullet };
}

// 战斗逻辑
function useFighting(
  enemyPlanes, 
  bullets, 
  enemyPlaneBullets, 
  planeInfo, 
  emit, 
  gameOverCallBack
) {
  const handlerTicker = () => {
    moveBullets(bullets)
    moveBullets(enemyPlaneBullets)
    moveEnemyPlane(enemyPlanes)
    // 游戏主循环
    enemyPlanes.forEach((enemyInfo) => {

      // 碰撞检测
      // 矩形碰撞 -- 算法(不严谨)
      if (hitTestObject(enemyInfo, planeInfo)) {
        // 游戏结束
        emit("changePage", "EndPage");
      }
    });

    // 移动我方子弹
    bullets.forEach((bulletInfo) => {
      bulletInfo.y--;
    });

    // 我方子弹碰撞检测
    bullets.forEach((bulletInfo, bulletIndex) => {
      // 和敌机碰撞
      enemyPlanes.forEach((enemyInfo, enemyIndex) => {
        const isIntersect = hitTestObject(bulletInfo, enemyInfo)
        if (isIntersect) {
          // 我方子弹和敌方飞机消失
          bullets.splice(bulletIndex, 1);

          // 敌机减血后销毁
          enemyInfo.life--;
          if (enemyInfo.life <= 0) {
            enemyPlanes.splice(enemyIndex, 1);
          }
        }
      });

      // 和敌方子弹碰撞
      enemyPlaneBullets.forEach((enemyBullet, index) => {
        const isIntersect = hitTestObject(bulletInfo, enemyBullet)
        if (isIntersect) {
          // 我方子弹和敌方子弹消失
          bullets.splice(bulletIndex, 1);
          enemyPlaneBullets.splice(index, 1)
        }
      })
    });

    const hitSelfHandle = (enemyObject) => {
      const isInersect = hitTestObject(planeInfo, enemyObject)
      if (isInersect) {
        gameOverCallBack && gameOverCallBack()
      }
    }
  
    enemyPlaneBullets.forEach((enemyBullet, enemyIndex) => {
      hitSelfHandle(enemyBullet)
    })
  
    enemyPlanes.forEach((enemyPalneInfo, enemyIndex) => {
      hitSelfHandle(enemyPalneInfo)
    })
  };

  // 页面渲染时开始移动并检测
  onMounted(() => {
    // 敌方飞机移动
    game.ticker.add(handlerTicker);
  });

  // 销毁时停止计时器
  onUnmounted(() => {
    // 敌方飞机销毁定时
    game.ticker.remove(handlerTicker);
  });
}
